﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xeralabs.Core.Events;

namespace Xeralabs.Core.Entities
{
    internal sealed class EntityManager : GDESKEntity
    {
        #region Entity Comparer
        private class EntityComparer : IEqualityComparer<ulong>
        {
            public bool Equals(ulong x, ulong y)
            {
                return (x == y);
            }

            public int GetHashCode(ulong obj)
            {
                return obj.GetHashCode();
            }
        }
        #endregion

        #region Singleton
        private static EntityManager _instance = null;

        public static ulong SingletonGUID
        {
            get
            {
                if (_instance == null)
                {
                    throw new NotInitializedException();
                }
                return _instance.GUID64;
            }
        }

        public static bool Initialize()
        {
            if (_instance == null)
            {
                _instance = new EntityManager();
                _instance.SetGUID64(1);
                _instance._entities.Add(_instance.GUID64, _instance);
            }
            return _instance != null;
        }

        public static EntityManager GetSingleton()
        {
            if (_instance == null)
            {
                throw new NotInitializedException();
            }
            return _instance;
        }

        //Not Creable
        private EntityManager()
        {
            _entities = new Dictionary<ulong, GDESKEntity>(new EntityComparer());
        }
        #endregion

        public GDESKEntity this[ulong index] { get { return _entities[index]; } }

        private Dictionary<ulong, GDESKEntity> _entities;

        internal void AddEntity(GDESKEntity entity)
        {
            try
            {
                _entities.Add(entity.GUID64, entity);
            }
            catch { }
        }

        #region GDESKEntity
        protected override void SendEvent(IMessage message)
        {
            base.SendEvent(message);
        }
        protected override void SendEvent(ulong target, double time, IMessage message)
        {
            base.SendEvent(target, time, message);
        }
        protected override void SendEvent(ulong target, double time, Priority priority, IMessage message)
        {
            base.SendEvent(target, time, priority, message);
        }
        protected override void SendEvent(ulong target, IMessage message)
        {
            base.SendEvent(target, message);
        }

        protected override void ReciveEvent(IEvent e)
        {
            if (e.Message is EndMessage)
            {
                EndMessage msg = (EndMessage)e.Message;
                if (msg.Ended && msg.EntityGUID != default(ulong))
                {
                    FinalizeEntity(e.Sender);
                }
            }
            base.ReciveEvent(e);
        }

        private void FinalizeEntity(ulong guid)
        {
            if (this.GUID64 != guid)
            {
                _entities.Remove(guid);
                if (_entities.Count == 1)
                {
                    EndMessage msg = new EndMessage()
                    {
                        Ended = true,
                        EntityGUID = GUID64
                    };
                    SendEvent(this.GUID64, 0.0, Priority.Kernel, msg);
                }
            }
            else if (this.GUID64 == guid)
            {
                _entities.Remove(this.GUID64);
                XGDESK.Ended();
            }
        }

        protected override bool FinalizeEntity()
        {
            if (_entities.Count > 1)
            {
                foreach (GDESKEntity entity in _entities.Values)
                {
                    if (entity.GUID64 != this.GUID64)
                        SendEvent(entity.GUID64, 0.0, Priority.Kernel | Priority.High, new EndMessage());
                }
                return false;
            }
            else
                return true;
        }
        #endregion

    }
}
